package cn.bby.tools.dialog;

import cn.bby.tools.dialog.common.BaseFieldParseDialog;
import cn.bby.tools.component.BaseValidationComponent;
import cn.bby.tools.component.ClassChooseComponent;
import cn.bby.tools.service.StateManagementService;
import cn.bby.tools.utils.MessageUtil;
import cn.hutool.core.util.StrUtil;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.MessageDialogBuilder;
import com.intellij.openapi.ui.ValidationInfo;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiField;
import com.intellij.ui.DocumentAdapter;
import com.intellij.ui.components.JBScrollPane;
import com.intellij.util.ui.JBUI;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import javax.swing.*;
import javax.swing.event.DocumentEvent;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 实体类字段生成对话框
 * 用于根据文本内容生成实体类字段
 *
 * @author ben
 * @version 1.0
 */
public class GenEntityFieldDialog extends BaseFieldParseDialog {
    private final GenEntityFieldState state = StateManagementService.getInstanceState().genEntityState;

    private final Project project;

    private final ClassChooseComponent sourceClassChoose;
    private final ClassChooseComponent targetClassChoose;

    @Override
    protected @NotNull Action @NotNull [] createActions() {
        // 创建自定义按钮：复制并关闭 和 关闭
        DialogWrapperAction gen = new DialogWrapperAction(MessageUtil.getMessage("message.Generate")) {
            @Override
            protected void doAction(ActionEvent e) {
                if (isValidError()) {
                    return;
                }
                saveState();
                Result result = doGen(true);
                PsiClass targetClass = targetClassChoose.getSelClass();
                boolean ask = MessageDialogBuilder.yesNo("结果", "成功添加字段：" + result.success + "\n\n失败字段：" + result.fail
                                + "\n\n是否打开类：[%s]？".formatted(targetClass.getName()))
                        .yesText("打开")
                        .noText("取消")
                        .ask(project);
                if (ask) {
                    //打开目的类
                    targetClass.navigate(true);
                }
                close(OK_EXIT_CODE);
            }
        };

        DialogWrapperAction closeAction = new DialogWrapperAction(MessageUtil.getMessage("message.Close")) {
            @Override
            protected void doAction(ActionEvent e) {
                saveState();
                doCancelAction();
            }
        };

        myOKAction = gen;
        return new Action[]{gen, closeAction};
    }

    /**
     * 构造函数
     *
     * @param project 项目实例
     */
    public GenEntityFieldDialog(@Nullable Project project) {
        super(project, MessageUtil.getMessage("action.BBY.GenEntityFieldAction.text"));
        this.project = project;
        sourceClassChoose = new ClassChooseComponent(project, "message.SourceClass");
        targetClassChoose = new ClassChooseComponent(project, "message.TargetClass");
        init();
    }


    @Override
    public void saveState() {
        PsiClass sourceClass = sourceClassChoose.getSelClass();
        PsiClass targetClass = targetClassChoose.getSelClass();
        if (sourceClass != null) {
            state.lastSourceClass = sourceClass.getQualifiedName();
        }
        if (targetClass != null) {
            state.lastTargetClass = targetClass.getQualifiedName();
        }
        state.selectText = getSourceText();
    }

    @Override
    public void loadState() {
        if (StrUtil.isEmpty(targetClassChoose.getSelClassName())) {
            targetClassChoose.setSelClass(state.lastTargetClass);
        }
        if (StrUtil.isEmpty(sourceClassChoose.getSelClassName())) {
            sourceClassChoose.setSelClass(state.lastSourceClass);
        }
        setSourceText(state.selectText);
    }

    @Override
    protected @Nullable JComponent createCenterPanel() {
        JPanel panel = new JPanel(new GridBagLayout());
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.insets = JBUI.insets(5);
        gbc.anchor = GridBagConstraints.WEST;

        // 初始化组件
        initializeFields();

        // 创建按钮
        JButton parseButton = new JButton(MessageUtil.getMessage("↓↓  " + MessageUtil.getMessage("message.Test") + "  ↓↓"));

        // 添加源类选择行
        gbc.gridx = 0;
        gbc.gridy = 0;
        gbc.gridwidth = 3;
        panel.add(sourceClassChoose, gbc);
        gbc.gridy++;
        panel.add(targetClassChoose, gbc);

        // 添加选中文本行（放在最前面）
        gbc.gridx = 0;
        gbc.gridy++;
        gbc.fill = GridBagConstraints.BOTH;
        gbc.gridwidth = 3;
        gbc.weightx = 1.0;
        panel.add(sourceParseUi, gbc);

        // 添加解析按钮
        gbc.gridx = 0;
        gbc.gridy++;
        gbc.weightx = 1.0;
        panel.add(parseButton, gbc);

        // 添加结果显示区域
        gbc.gridx = 0;
        gbc.gridy++;
        gbc.gridwidth = 3;
        panel.add(new JLabel(MessageUtil.getMessageSuffix("message.ParseResult")), gbc);

        gbc.gridy++;
        gbc.fill = GridBagConstraints.BOTH;
        gbc.weighty = 1.0;
        gbc.weightx = 1.0;
        JBScrollPane resultScrollPane = new JBScrollPane(resultTextArea);
        panel.add(resultScrollPane, gbc);

        // 添加事件监听器
        addEventListeners(parseButton);

        loadState();
        return panel;
    }

    @Override
    protected @Nullable ValidationInfo doValidate() {
        for (BaseValidationComponent component : List.of(sourceParseUi, sourceClassChoose, targetClassChoose)) {
            ValidationInfo validationInfo = component.doValidate();
            if (validationInfo != null) {
                return validationInfo;
            }
        }
        return super.doValidate();
    }

    /**
     * 初始化文本字段
     */
    private void initializeFields() {
        resultTextArea.setEditable(false);
        resultTextArea.setBorder(BorderFactory.createLoweredBevelBorder());
        resultTextArea.setRows(10);
        resultTextArea.setColumns(75);
    }

    /**
     * 添加事件监听器
     *
     * @param parseButton        解析按钮
     */
    private void addEventListeners(JButton parseButton) {
        parseButton.addActionListener(e -> {
            if (isValidError()) {
                resultTextArea.setText("请检查输入！");
                return;
            }
            //触发校验
            initValidation();
            Result result = doGen(false);
            StringBuilder res = new StringBuilder();
            res.append("匹配项：\n");
            for (String s : result.success()) {
                res.append(s).append(",");
            }
            res.append("\n\n未匹配项：\n");
            for (String f : result.fail) {
                res.append(f).append(",");
            }
            res.append("\n\n已存在：\n");
            for (String f : result.exists) {
                res.append(f).append(",");
            }
            resultTextArea.setText(res.toString());
            resultTextArea.setCaretPosition(0);
        });
//        selectedText改变后
        sourceParseUi.addDocumentListener(new DocumentAdapter() {
            @Override
            protected void textChanged(@NotNull DocumentEvent e) {
                sourceParseUi.parseCheck();
                isValidError();
            }
        });
    }


    /**
     * 获取源类
     *
     * @return 源类
     */
    public PsiClass getSourceClass() {
        return sourceClassChoose.getSelClass();
    }

    /**
     * 获取目标类
     *
     * @return 目标类
     */
    public PsiClass getTargetClass() {
        return targetClassChoose.getSelClass();
    }

    /**
     * 设置选中文本
     *
     * @param text 文本内容
     */
    public void setSelectedText(String text) {
        setSourceText(text);
    }

    /**
     * 设置源类
     *
     * @param qualifiedName 类全限定名
     */
    public void setSourceClass(String qualifiedName) {
        sourceClassChoose.setSelClass(qualifiedName);
    }

    /**
     * 设置目标类
     *
     * @param qualifiedName 类全限定名
     */
    public void setTargetClass(String qualifiedName) {
        targetClassChoose.setSelClass(qualifiedName);
    }

    /**
     * 获取选中文本
     *
     * @return 文本内容
     */
    public String getSelectedText() {
        return getSourceText();
    }


    record Result(java.util.List<String> success, java.util.List<String> fail, Set<String> exists) {
    }

    private Result doGen(boolean write) {
        PsiClass selectedClass = getSourceClass();
        PsiClass targetClass = getTargetClass();
        java.util.List<String> fields = parseCols();
        Map<String, PsiField> fieldMap = Arrays.stream(selectedClass.getAllFields())
                .collect(Collectors.toMap(f -> f.getName().toLowerCase(), field -> field));

        Set<String> existFields = Arrays.stream(targetClass.getAllFields()).map(f -> f.getName().toLowerCase())
                .collect(Collectors.toSet());
        java.util.List<String> cols = fields.stream().filter(f -> !existFields.contains(f.toLowerCase()))
                .distinct()
                .toList();
        java.util.List<String> success = new ArrayList<>(cols.size());
        List<String> fail = new ArrayList<>(cols.size());
        if (cols.isEmpty()) {
            return new Result(success, fail, existFields);
        }
        if (write) {
            //获取文件路径
            // 使用WriteCommandAction包装PSI修改操作
            WriteCommandAction.runWriteCommandAction(selectedClass.getProject(), () -> {
                // 获取文件路径
                for (String col : cols) {
                    PsiField field = fieldMap.get(col);
                    if (field != null) {
                        targetClass.add(field);
                        success.add(col);
                    } else {
                        fail.add(col);
                    }
                }
            });
            return new Result(success, fail, existFields);
        }
        for (String col : cols) {
            PsiField field = fieldMap.get(col);
            if (field != null) {
                success.add(col);
            } else {
                fail.add(col);
            }
        }
        return new Result(success, fail, existFields);
    }

    public static class GenEntityFieldState {
        public String lastSourceClass = "";
        public String lastTargetClass = "";
        public String selectText = "";
    }
}